from mongokit import *
import datetime
import hashlib, hmac, base64, re
from whirlwind.db.mongo import Mongo
from tornado import options
from UtilExtension.GravatarImage import GetGravatarUrl

"""
Model for user.
"""

'''
normalizes a username or email address
'''
def normalize(username):
    if not username :
        return None
    #allow legal email address
    name = username.strip().lower()
    name = re.sub(r'[^a-z0-9\\.\\@_\\-~#]+', '', name)
    name = re.sub('\\s+', '_',name)
    
    #don't allow $ and . because they screw up the db.
    name = name.replace(".", "")
    name = name.replace("$", "")
    return name;

# Validator
def create_email_validator(value):
    """
    Validator for email.
    """
    email = \
    re.compile(r"(?:^|\s)[-a-z0-9_.]+@(?:[-a-z0-9]+\.)+[a-z]{2,6}(?:\s|$)",\
               re.IGNORECASE)
    if not bool(email.match(value)):
        raise ValidationError("%s: The email is not valid.")
    if User.email_exist(email):
        raise ValidationError("%s: The email is exist.")
    return True

def simple_email_validator(value):
    """
    Validator for email.
    """
    email = \
    re.compile(r"(?:^|\s)[-a-z0-9_.]+@(?:[-a-z0-9]+\.)+[a-z]{2,6}(?:\s|$)",\
               re.IGNORECASE)
    if not bool(email.match(value)):
        raise ValidationError("%s: The email is not valid.")
    return True


def password_validator(value):
    """
    Validator for Password
    """
    if len(value) < 6:
        raise ValidationError("%s: Password is too short. At least 6 characts.")
    return True

@Mongo.db.connection.register
class User(Document):

    # Collection name
    __collection__ = 'myusers'
    
    structure = {
        '_id':unicode,     # email
        'username':unicode,   # username
        'roles':list,      # roles 
        'password':unicode, #password
        'created_at':datetime.datetime,    # time for creation
        'history' : { # login history
                  'last_login' : datetime.datetime,
                  'num_logins' : long
                  },
        'suspended_at':datetime.datetime, # suspended time
        'profile': { # my profile
                 'myimg':unicode,
                 'locale':unicode,
                 'interests':list,
                 'level':int,
                 'credit':int,
                 'timezone':unicode
                }, 
        'mykeys':list # my app keys
    }
    
    required = ['_id', 'username', 'password', 'created_at']

    default_values = {
        'history.num_logins' : long(0),
        'profile.myimg' : u'',
        'profile.locale' : u'en_US',
        'profile.interests' : [],
        'profile.level' : 0,
        'profile.credit' : 0,
        'profile.timezone' : u'Asia/Singapore'
    }
    
    validators = {
        '_id' : create_email_validator,
        'password' : password_validator
    }

    raise_validation_errors = False

    use_dot_notation = True
    
    @staticmethod
    def normalize(username):
        return normalize(username)
        
    
    @staticmethod
    def lookup(email):
        return Mongo.db.ui.User.find_one({'_id' : email})
        
    @staticmethod
    def extract_username(email):
        """
        Extract username from email.
        """
        return email.split('@')[0]
        
    '''
    creates a new user instance. unsaved
    '''
    @staticmethod
    def instance(username, password, email):
        user = Mongo.db.ui.User()
        user.roles = ['nonactive']
        user['_id'] = email
        if len(password) < 6:
            user.password = unicode(password)
        else:
            user.password = User.hash_password(password)
        user.username = username 
        user.created_at = datetime.datetime.utcnow()
        user.history.last_login = user.created_at
        return user
    
    @staticmethod
    def email_exist(email):
        """
        Check if the username exist.
        """
        if User.lookup(email):
            return True
        else:
            return False
    
    @staticmethod
    def create_user(username, password, email):
        """
        staticmethod for create user.
        """
        pass

    @staticmethod
    def hash_password(password):
        return unicode(hashlib.sha1(password).hexdigest())

    def add_role(self, role):
        if not self.get('roles', False):
            self['roles'] = []
        
        if role in self['roles'] :
            return
        self['roles'].append(role)
        
    def remove_role(self, role):
        if not self.get('roles', False):
            self['roles'] = []
        try :
            while True:
                self['roles'].remove(role)
        except :
            pass
        
    def has_role(self, role):
        if not self.get('roles', False):
            self['roles'] = []
        if isinstance(role, basestring):
            return role in self['roles']
        else:
            for r in role:
                if r in self['roles']:
                    return True
    
    def name(self):
        return self._id
    
    def get_timezone(self):
        tz = self.get('profile.timezone', None)
        if tz :
            return tz
        return u'Asia/Singapore'
                
    def is_suspended(self):
        if self.get('suspended_at', None) == None :
            return False
        return self.suspended_at < datetime.datetime.utcnow()

    def is_nonactive(self):
        if self['roles'][0] == 'nonactive':
            return True
        return False

    def get_imagelink(self, size, default):
        return GetGravatarUrl(self['_id'], size, default)
